/**
 * This software is released under the terms of the MIT License
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @copyright  2009-2011 Roberto Perpuly
 * @license    http://www.opensource.org/licenses/mit-license.php The MIT License
 */
#ifndef __RUNCONSOLEFEATURECLASS_H__
#define __RUNCONSOLEFEATURECLASS_H__

/**
@file
Subclass of RunConsolePanelGeneratedClass, which is generated by wxFormBuilder.
*/

#include <features/wxformbuilder/RunConsoleFeatureForms.h>
#include <features/FeatureClass.h>
#include <widgets/ProcessWithHeartbeatClass.h>
#include <vector>

/** Implementing RunConsolePanelGeneratedClass */

namespace mvceditor {

// defined below
class RunConsoleFeatureClass;

/**
 * Class that represents a command to be run in the 
 * 'console' (CLI).
 */
class CliCommandClass {

public:

	/**
	 * Binary to be run. This may be a full path, or just the
	 * binary name if the binary is already in the PATH.
	 */
	wxString Executable;

	/**
	 * all of the arguments to give to the executable
	 */
	wxString Arguments;

	/**
	 * A short human-friendly description of the command. This is
	 * given by the user; it is not guaranteed to be unique.
	 */
	wxString Description;

	/**
	 * if TRUE, then when the console window is created for this command
	 * the command will NOT be run. This gives the user a chance to
	 * add runtime arguments.
	 */
	bool WaitForArguments;

	/**
	 * if TRUE, this item will show up in the toolbar. Note that the order 
	 * is determined by the position in the list of commands.
	 */
	bool ShowInToolbar;
	
	CliCommandClass();

	void Copy(const CliCommandClass& src);
	
	/**
	 * @return the command to be executed
	 */
	wxString CmdLine() const;

};

/**
 * This is the dialog where the user can edit a
 * run console command.
 */
class CliCommandEditDialogClass : public CliCommandEditDialogGeneratedClass {

public:

	CliCommandEditDialogClass(wxWindow* parent, int id, mvceditor::CliCommandClass& command);

protected:

	void OnOkButton(wxCommandEvent& event);
	void OnHelpButton(wxCommandEvent& event);
	void OnFileChanged(wxFileDirPickerEvent& event);

};

/**
 * This is the dialog where the user can re-order console commands, add, or remove
 * commands also.
 */
class CliCommandListDialogClass : public CliCommandListDialogGeneratedClass {

public:

	CliCommandListDialogClass(wxWindow* parent, int id, std::vector<mvceditor::CliCommandClass>& commands);


protected:

	// to manage the list of commands
	// UP & DOWN control the order of the commands
	// in the toolbar
	void OnUpButton(wxCommandEvent& event);
	void OnDownButton(wxCommandEvent& event);
	void OnAddButton(wxCommandEvent& event);
	void OnDeleteButton(wxCommandEvent& event);
	void OnOkButton(wxCommandEvent& event);
	void OnEditButton(wxCommandEvent& event);
	void OnListDoubleClick(wxCommandEvent& event);
	void OnHelpButton(wxCommandEvent& event);

private:

	/**
	 * List of commands that are bound to this dialog. They will only be 
	 * modified when the user clicks OK
	 */
	std::vector<mvceditor::CliCommandClass>& Commands;

	/**
	 * List of commands that the user modifies.
	 */
	std::vector<mvceditor::CliCommandClass> EditedCommands;
	
	/**
	 * populates the Commands listbox using the data 
	 * from Commands
	 */
	void FillList();
	
};

/**
 * Keeps track of the position of a file name in the output.
 */
class FileNameHitClass {

public:

	/**
	 * The 0-based index into output string. This is the start of the file name
	 */
	int32_t StartIndex;

	/**
	 * The number of characters in the file name
	 */
	int32_t Length;

	FileNameHitClass();

};
	
class RunConsolePanelClass : public RunConsolePanelGeneratedClass {
protected:
	
	/**
	 * Handle the clear button.
	 */
	void OnClear(wxCommandEvent& event);

public:
	
	/*
	 * @param parent the parent of this pane
	 * @param id window ID
	 * @param gauge to show progress to the user. This class will NOT own the pointer.
	 * @param feature the feature, used to add commands
	 */
	RunConsolePanelClass(wxWindow* parent, int id,
		mvceditor::StatusBarWithGaugeClass* gauge, mvceditor::RunConsoleFeatureClass& feature);

	/**
	 * Set to run the given command
	 * 
	 * @param cmdLine entire command line to run
	 * @aparam waitForArgument if TRUE then
	 */
	void SetToRunCommand(const wxString& cmdLine, bool waitForArguments);
	
	/**
	 * Handle the 'Run' button
	 */
	void RunCommand(wxCommandEvent& event);
	
	/**
	 * when the page is closed perform cleanup. This means
	 * clean up the child process and any open gauges
	 */
	void OnPageClose(wxAuiNotebookEvent& evt);

	/**
	 * When the user clicks on the store button save the current command.
	 */
	void OnStoreButton(wxCommandEvent& event);

	/**
	 * @return the command that is being run or that the user
	 *  is typing in
	 */
	wxString GetCommand() const;

private:
		
	/**
	 * The command to run
	 */
	wxString CommandString;
	
	/**
	 * Used to run the process asynchronously
	 */
	ProcessWithHeartbeatClass ProcessWithHeartbeat;

	/**
	 * To show progress to the user.
	 */
	StatusBarWithGaugeClass* Gauge;
	
	/**
	 * To save the current command to be persisted.
	 */
	RunConsoleFeatureClass& Feature;

	/**
	 * Save the hits so that we can traverse through them
	 */
	std::vector<mvceditor::FileNameHitClass> FileNameHits;
	
	/**
	 * the current PID of the async process.
	 */
	long int CurrentPid;
	
	/**
	 * Gauge id for this instance of RunConsole. Each run console will have its own gauge to update
	 * 
	 * @var int
	 */
	int IdProcessGauge;
	
	/**
	 * called when the process ends.
	 */
	void OnProcessComplete(wxCommandEvent& event);

	/**
	 * called when the process ends.
	 */
	void OnProcessFailed(wxCommandEvent& event);
	
	/**
	 * Check running process output. Will poll process output and display it.
	 * 
	 * @param wwCommandEvent& event
	 */
	void OnProcessInProgress(wxCommandEvent& event);

	/**
	 * @param text to append to the output. This method will format filenames
	 * so that they are distinguishable from other text.
	 */
	void AppendText(const wxString& text);
	
	/**
	 * @return the regular expression that will match a file name. The 
	 * matche files will have PHP, CSS, or SQL extensions as allowed
	 * by the current project's file name wildcards.
	 */
	UnicodeString FileNameRegularExpression();

	/**
	 * on mouse events, check to see if the mouse is hovered over a file name
	 * if so, then change the cursor
	 */
	void OnMouseMotion(wxMouseEvent& event);
	
	/**
	 * Opens the file that was clicked on
	 */
	void OnLeftDown(wxMouseEvent& event);

	/**
	 * Get the filename hit from the mouse event
	 *
	 * @param evt the mouse position
	 * @return the filename hit that is located at the mouse position
	 */
	mvceditor::FileNameHitClass HitAt(wxMouseEvent& evt);
	
	DECLARE_EVENT_TABLE()
};

class RunConsoleFeatureClass : public FeatureClass {

public:

	/**
	 * Constructor
 	 */
	RunConsoleFeatureClass(mvceditor::AppClass& app);
	
	/**
	 * Add menu items
	 */
	void AddNewMenu(wxMenuBar* menuBar);
	
	/**
	 * Add items to the toolbar
	 */
	void AddToolBarItems(wxAuiToolBar* toolBar);

	void AddKeyboardShortcuts(std::vector<DynamicCmdClass>& shortcuts);

	void LoadPreferences(wxConfigBase* config);

	/**
	 * Add a new command to the list (but does not persist
	 * the list to disk)
	 */
	void AddCommand(const mvceditor::CliCommandClass& command);

	/**
	 * Saves the CLI commands to the [global] config
	 */
	void PersistCommands();

	/**
	 * Open a file.
	 */
	void LoadPage(const wxString& fileName);
	
private:
				
	/**
	 * handler for the menu
	 */
	void OnRunFileAsCli(wxCommandEvent& event);
	
	/**
	 * Always run in a new console window
	 */
	void OnRunFileAsCliInNewWindow(wxCommandEvent& event);

	/**
	 * @param command runs the given command and shows the output
	 *        panel. Note that the command may not actually start running
	 *        if waitForArguments is set.
	 * @param waitForAguments boolean if true then command will not run
	 *        if false, command will run right away
	 * @param inNewWindow, if TRUE then a new console output window will
	 * be created. Otherwise, the current output window may be used.
	 */
	void RunCommand(const wxString& cmdLine, bool waitForArguments, bool inNewWindow);
	
	/**
	 * disable menus when source code notebook is empty
	 */
	void OnUpdateUi(wxUpdateUIEvent& event);

	/**
	 * show the dialog CRUD for commands
	 */
	void OnRunSavedCommands(wxCommandEvent& event);

	/**
	 * When another feature wants to run a process; it will send a command
	 * event of type EVENT_CMD_RUN_COMMAND. This method will handle 
	 * these events from other features and start the process.
	 */
	void OnAppCommandRun(wxCommandEvent& event);

	/**
	 * synchronized the command panel buttons with those
	 * from the Commands list. Any buttons for the removed 
	 * commands are removed and buttons for new commands are added.
	 */
	void FillCommandPanel();

	/**
	 * Handles the click of the saved command buttons
	 */
	void OnCommandButtonClick(wxCommandEvent& evt);

	/**
	 * The list of commands to be persisted.
	 */
	std::vector<mvceditor::CliCommandClass> CliCommands;
			
	/**
	 * Our menu items
	 */
	wxMenuItem* RunCliMenuItem;
	wxMenuItem* RunCliWithArgsMenuItem;
	wxMenuItem* RunCliInNewWindowMenuItem;
	wxMenuItem* RunCliWithArgsInNewWindowMenuItem;

	wxAuiToolBar* CommandToolbar;

	DECLARE_EVENT_TABLE()
};

}
#endif // __RUNCONSOLEFEATURECLASS_H__
